module common_rrarb #(
    parameter REQ_W = 16,
    parameter MODE  = 0
) (
    input logic clk,
    input logic rst_n,
    input logic [REQ_W-1:0] req,
    input logic ack,
    output logic [REQ_W-1:0] gnt
);

    logic [REQ_W-1:0] req_r;

    generate
        if (MODE == 1) begin : KEEP_MODE
            logic             keep;
            logic [REQ_W-1:0] req_old;
            always_ff @(posedge clk or negedge rst_n) begin
                if (!rst_n) begin
                    req_r <= 0;
                    keep  <= 0;
                end else if (ack) begin
                    keep <= 0;
                end else if ((|req) && (~keep)) begin
                    keep    <= 1;
                    req_old <= req;
                end
            end
            assign req_r = keep ? req_old : req;
        end else begin : NO_KEEP_MODE
            assign req_r = req;
        end
    endgenerate

    logic [REQ_W-1:0] req_power;
    logic [REQ_W-1:0] req_after_power;
    logic [REQ_W-1:0] old_msk;
    logic [REQ_W-1:0] new_msk;
    logic [REQ_W-1:0] old_grant_work;
    logic [REQ_W-1:0] old_grant;
    logic [REQ_W-1:0] new_grant;

    assign req_after_power = req_r & req_power;
    assign old_msk         = {req_after_power[REQ_W-2:0] | old_grant_work[REQ_W-2:0], 1'b0};
    assign new_msk         = {req_r[REQ_W-2:0] | new_msk[REQ_W-2:0], 1'b0};
    assign old_grant_work  = !req_after_power;
    assign old_grant       = ~old_msk & old_grant_work;
    assign new_grant       = ~new_msk & req_r;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            req_power <= 'd0;
        end else if (ack) begin
            if (old_grant_work) begin
                req_power <= old_msk;
            end
            if (~req) begin
                req_power <= new_msk;
            end
        end
    end
endmodule
